" Vim script file                                           vim600:fdm=marker:
" FileType:     XML
" Author:       Rene de Zwart <renez (at) lightcon.xs4all.nl>
" Maintainer:   Rene de Zwart <renez (at) lightcon.xs4all.nl>
" Last Change:  Date: 2009-11-12
" Version:      Revision: 1.37
"
" Licence:      This program is free software; you can redistribute it
"               and/or modify it under the terms of the GNU General Public
"               License.  See http://www.gnu.org/copyleft/gpl.txt
" Credits:      Devin Weaver <vim (at) tritarget.com>  et all
"               for the original code.  Guo-Peng Wen for the self
"               install documentation code.
"               Bart vam Deenen for makeElement function
"               Rene de Zwart


" Observation   - If you want to do something to a match pair most of the time
"               you must do first the close tag. Because doing first the open
"               tag could change the close tag position.

" NOTE          with filetype index on de standard indent/html.vim interferes
"               with xml.vim. You can
"                 1) set filetype indent off in .vimrc
"                 2) echo "let b:did_indent = 1" > .vim/indent/html.vim


" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
  finish
endif
let b:did_ftplugin = 1

setlocal commentstring=<!--%s-->
setlocal iskeyword=@,48-57,_,192-255,58,-

" XML:  thanks to Johannes Zellner and Akbar Ibrahim
" - case sensitive
" - don't match empty tags <fred/>
" - match <!--, --> style comments (but not --, --)
" - match <!, > inlined dtd's. This is not perfect, as it
"   gets confused for example by
"       <!ENTITY gt ">">
if exists("loaded_matchit")
    let b:match_ignorecase=0
    let b:match_words =
     \  '<:>,' .
     \  '<\@<=!\[CDATA\[:]]>,'.
     \  '<\@<=!--:-->,'.
     \  '<\@<=?\k\+:?>,'.
     \  '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
     \  '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
endif

function! s:SID()
  return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfunction

" Script rgular expresion used. Documents those nasty criters      {{{1
let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
" Don't check for quotes around attributes!!!
let s:Attrib =  '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
let s:CloseTag = '<\/[^>]*'. s:NoSlashBeforeGt
let s:SpaceInfront = '^\s*<'
let s:EndofName = '\($\|\s\|>\)'

" Buffer variables                                                  {{{1
let b:emptyTags='^\(area\|base\|br\|col\|command\|embed\|hr\|img\|input\|keygen\|link\|meta\|param\|source\|track\|wbr\)$'
let b:firstWasEndTag = 0
let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
let b:haveAtt = 0
let b:lastTag = ""
let b:lastAtt = ""
let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
let b:xml_use_xhtml = 0
if exists('g:xml_use_xhtml')
  let b:xml_use_xhtml = g:xml_use_xhtml
elseif &filetype == 'xhtml'
  let b:xml_use_xhtml = 1
en

if ! exists("b:xmlPluginMappedKeys")
  let b:xmlPluginMappedKeys = []
endif

let b:undo_ftplugin = "setlocal cms< isk<"
  \ . "| if exists('b:match_ignorecase') | unlet b:match_ignorecase | endif"
  \ . "| if exists('b:match_words') | unlet b:match_words | endif"
  \ . "| call <SNR>" . s:SID() . "_unmapKeys()"
  \ . "| unlet b:xmlPluginMappedKeys"



" NewFileXML -> Inserts <?xml?> at top of new file.                  {{{1
if !exists("*NewFileXML")
function! NewFileXML( )
    " Where is g:did_xhtmlcf_inits defined?
    if &filetype == 'xml' ||
      \ (!exists ("g:did_xhtmlcf_inits") &&
      \ b:xml_use_xhtml &&
      \ (&filetype =~ 'x\?html'))
        if append (0, '<?xml version="1.0"?>')
            normal! G
        endif
    endif
endfunction
endif



" Callback -> Checks for tag callbacks and executes them.            {{{1
if !exists("*s:Callback")
function! s:Callback( xml_tag, isHtml )
    let text = 0
    if a:isHtml == 1 && exists ("*HtmlAttribCallback")
        let text = HtmlAttribCallback (a:xml_tag)
    elseif exists ("*XmlAttribCallback")
        let text = XmlAttribCallback (a:xml_tag)
    endif
    if text != '0'
        execute "normal! i " . text ."\<Esc>l"
    endif
endfunction
endif

" SavePos() saves position  in bufferwide variable                        {{{1
fun! s:SavePos()
  retu 'call cursor('.line('.').','. col('.'). ')'
endf

" findOpenTag()                         {{{1
fun! s:findOpenTag(flag)
  call search(s:OpenTag,a:flag)
endf

" findCloseTag()                         {{{1
fun! s:findCloseTag(flag)
  call search(s:CloseTag,a:flag)
endf

" GetTagName() Gets the tagname from start position                     {{{1
"Now lets go for the name part. The namepart are xmlnamechars which
"is quite a big range. We assume that everything after '<' or '</'
"until the first 'space', 'forward slash' or '>' ends de name part.
if !exists('*s:GetTagName')
fun! s:GetTagName(from)
    let l:end = match(getline('.'), s:EndofName,a:from)
    return strpart(getline('.'),a:from, l:end - a:from )
endf
en
" hasAtt() Looks for attribute in open tag                           {{{1
" expect cursor to be on <
fun! s:hasAtt()
  "Check if this open tag has attributes
  let l:line = line('.') | let l:col = col('.')
  if search(b:tagName . s:ReqAttrib,'W') > 0
    if l:line == line('.') && l:col == (col('.')-1)
      let b:haveAtt = 1
    en
  en
endf


" TagUnderCursor()  Is there a tag under the cursor?               {{{1
" Set bufer wide variable
"  - b:firstWasEndTag
"  - b:tagName
"  - b:endcol & b:endline only used by Match()
"  - b:gotoCloseTag (if the tag under the cursor is one)
"  - b:gotoOpenTag  (if the tag under the cursor is one)
" on exit
"    - returns 1 (true)  or 0 (false)
"    - position is at '<'
if !exists('*s:TagUnderCursor')
fun! s:TagUnderCursor()
  let b:firstWasEndTag = 0
  let l:haveTag = 0
  let b:haveAtt = 0

  "Lets find forward a < or a >.  If we first find a > we might be in a tag.
  "If we find a < first or nothing we are definitly not in a tag

  if getline('.')[col('.') - 1] == '>'
    let b:endcol  = col('.')
    let b:endline = line('.')
    if getline('.')[col('.')-2] == '/'
        "we don't work with empty tags
      retu l:haveTag
    en
    " begin: gwang customization for JSP development
    if getline('.')[col('.')-2] == '%'
        "we don't work with jsp %> tags
      retu l:haveTag
    en
    " end: gwang customization for JSP development
    " begin: gwang customization for PHP development
    if getline('.')[col('.')-2] == '?'
        "we don't work with php ?> tags
      retu l:haveTag
    en
    " end: gwang customization for PHP development
  elseif search('[<>]','W') >0
    if getline('.')[col('.')-1] == '>'
      let b:endcol  = col('.')
      let b:endline = line('.')
      if getline('.')[col('.')-2] == '-'
        "we don't work with comment tags
        retu l:haveTag
      en
      if getline('.')[col('.')-2] == '/'
        "we don't work with empty tags
        retu l:haveTag
      en
    el
      retu l:haveTag
    en
  el
    retu l:haveTag
  en

  if search('[<>]','bW' ) >=0
    if getline('.')[col('.')-1] == '<'
      if getline('.')[col('.')] == '/'
        let b:firstWasEndTag = 1
        let b:gotoCloseTag = s:SavePos()
      elseif getline('.')[col('.')] == '?' ||  getline('.')[col('.')] == '!'
        "we don't deal with processing instructions or dtd
        "related definitions
        retu l:haveTag
      el
        let b:gotoOpenTag = s:SavePos()
      en
    el
      retu l:haveTag
    en
  el
    retu l:haveTag
  en

  "we have established that we are between something like
  "'</\?[^>]*>'

  let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
  "echo 'Tag ' . b:tagName

  "begin: gwang customization, do not work with an empty tag name
  if b:tagName == ''
    retu l:haveTag
  en
  "end: gwang customization, do not work with an empty tag name

  let l:haveTag = 1
  if b:firstWasEndTag == 0
    call s:hasAtt()
    exe b:gotoOpenTag
  en
  retu l:haveTag
endf
en

" Match(tagname) Looks for open or close tag of tagname               {{{1
" Set buffer wide variable
"  - b:gotoCloseTag (if the Match tag is one)
"  - b:gotoOpenTag  (if the Match tag is one)
" on exit
"    - returns 1 (true) or 0 (false)
"    - position is at '<'
if !exists('*s:Match')
fun! s:Match(name)
  let l:pat = '</\=' . a:name . s:OptAttrib
  if  b:firstWasEndTag
    exe b:gotoCloseTag
    let l:flags='bW'
    let l:level = -1
  el
    exe  'normal! '.b:endline.'G0'.(b:endcol-1).'l'
    let l:flags='W'
    let l:level = 1
  en
  while l:level &&  search(l:pat,l:flags) > 0
    let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
  endwhile
  if l:level
    echo "no matching tag!!!!!"
    retu l:level
  en
  if b:firstWasEndTag
    let b:gotoOpenTag = s:SavePos()
    call s:hasAtt()
    exe b:gotoOpenTag
  el
    let b:gotoCloseTag = s:SavePos()
  en
  retu l:level == 0
endf
en

" InComment()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:InComment')
fun! s:InComment()
let b:endcom=0
let b:begcom=0

  "Lets find forward a < or a >.  If we first find a > we might be in a comment.
  "If we find a < first or nothing we are definitly not in a Comment

  if getline('.')[col('.') - 1] == '>'
    if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
      let b:endcomcol=col('.')
      let b:endcomline=line('.')
      let b:endcom=1
      retu 1
    en
  elseif  getline('.')[col('.')-1] == '<' && getline('.')[col('.')]   == '!'
     \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
      let b:begcomcol= col('.')
      let b:begcomline=line('.')
      let b:begcom=1
      retu 1
  en
  "We are not standing on a begin/end comment
  "Is the first > an ending comment?
  if search('[<>]','W') >0
    if getline('.')[col('.')-1] == '>'
      if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
      let b:endcomcol=col('.')
      let b:endcomline=line('.')
      let b:endcom=1
        retu 1
      en
    en
  en
  "Forward is not a ending comment
  "is backward a starting comment

  if search('[<>]','bW' ) >=0
    if getline('.')[col('.')-1] == '<' && getline('.')[col('.')]   == '!'
     \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
      let b:begcomcol=col('.')
      let b:begcomline=line('.')
      let b:begcom=1
      retu 1
    en
  en
  retu 0
endf
en

" DelComment()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelComment')
fun! s:DelComment()

  let l:restore =  s:SavePos()
  if s:InComment()
    if b:begcom
      if search('-->','W' ) >=0
        normal! hh3x
        call cursor(b:begcomline,b:begcomcol)
        normal! 4x
        retu 1
      en
    el
      if search('<!--','bW' ) >=0
        normal! 4x
        call cursor(b:endcomline,b:endcomcol)
        normal! hh3x
        retu 1
      en
    en
  en
  exe l:restore
  retu 0
endf
en

" DelCommentSection()  Is there a Comment under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCommentSection')
fun! s:DelCommentSection()

  let l:restore =  s:SavePos()
  if s:InComment()
    let l:sentinel = 'XmLSeNtInElXmL'
    let l:len = strlen(l:sentinel)
    if b:begcom
      if search('-->','W' ) >=0
        exe "normal! f>a".l:sentinel."\<Esc>"
        call cursor(b:begcomline,b:begcomcol)
        exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
        exe "normal! ".l:len."x"
        retu 1
      en
    el
      if search('<!--','bW' ) >=0
        let l:restore =  s:SavePos()
        call cursor(b:endcomline,b:endcomcol)
        exe "normal! a".l:sentinel."\<Esc>"
        exe l:restore
        exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
        exe "normal! ".l:len."x"
        retu 1
      en
    en
  en
  exe l:restore
  retu 0
endf
en

" DelCData()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCData')
fun! s:DelCData()

  let l:restore =  s:SavePos()
  if s:InCData()
    if b:begdat
      if search(']]>','W' ) >=0
        normal! hh3x
        call cursor(b:begdatline,b:begdatcol)
        normal! 9x
        retu 1
      en
    el
      if search('<![CDATA[','bW' ) >=0
        normal! 9x
        call cursor(b:enddatline,b:enddatcol)
        normal! hh3x
        retu 1
      en
    en
  en
  exe l:restore
  retu 0
endf
en

" InCData()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:InCData')
fun! s:InCData()
let b:enddat=0
let b:begdat=0

  "Lets find forward a < or a >.  If we first find a > we might be in a comment.
  "If we find a < first or nothing we are definitly not in a Comment

  if getline('.')[col('.') - 1] == '>'
    if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
      let b:enddatcol=col('.')
      let b:enddatline=line('.')
      let b:enddat=1
      retu 1
    en
  elseif  getline('.')[col('.')-1] == '<'
    if  match(getline('.'),'<![CDATA[') > 0
      let b:begdatcol= col('.')
      let b:begdatline=line('.')
      let b:begdat=1
      retu 1
    en
  en
  "We are not standing on a begin/end comment
  "Is the first > aending comment?
  if search('[<>]','W') >0
    if getline('.')[col('.')-1] == '>'
      if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
      let b:enddatcol=col('.')
      let b:enddatline=line('.')
      let b:enddat=1
        retu 1
      en
    en
  en
  "Forward is not a ending datment
  "is backward a starting comment

  if search('[<>]','bW' ) >=0
    if getline('.')[col('.')-1] == '<'
      if  match(getline('.'),'<![CDATA[') > 0
    let l:newname = inputdialog('Found CDATA')
        let b:begdatcol=col('.')
        let b:begdatline=line('.')
        let b:begdat=1
        retu 1
      en
    en
  en
  retu 0
endf
en


" DelCDataSection()  Is there a CData under the cursor?               {{{1
"    - returns 1 (true)  or 0 (false)

if !exists('*s:DelCDataSection')
fun! s:DelCDataSection()

  let l:restore =  s:SavePos()
  if s:InCData()
    let l:sentinel = 'XmLSeNtInElXmL'
    let l:len = strlen(l:sentinel)
    if b:begdat
      if search(']]>','W' ) >=0
        exe "normal! f>a".l:sentinel."\<Esc>"
        call cursor(b:begdatline,b:begdatcol)
        exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
        exe "normal! ".l:len."x"
        retu 1
      en
    el
      if search('<![CDATA[','bW' ) >=0
        let l:restore =  s:SavePos()
        call cursor(b:enddatline,b:enddatcol)
        exe "normal! a".l:sentinel."\<Esc>"
        exe l:restore
        exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
        exe "normal! ".l:len."x"
        retu 1
      en
    en
  en
  exe l:restore
  retu 0
endf
en


" Matches()  Matches de tagname under de cursor                       {{{1
if !exists('*s:Matches')
fun! s:Matches()
  let l:restore =  s:SavePos()
  if s:TagUnderCursor()
    if s:Match(b:tagName)
      retu
    en
  en
  exe l:restore
endf
en

" MatchesVisual()  Matches de tagname under de cursor                       {{{1
if !exists('*s:MatchesVisual')
fun! s:MatchesVisual()
  let l:restore =  s:SavePos()
  if s:TagUnderCursor()
    if b:firstWasEndTag
      normal! f>
    en
    normal! gv
    if s:Match(b:tagName)
      if b:firstWasEndTag == 0
        normal! f>
      en
      retu
    en
    normal! v
  en
  exe l:restore
endf
en

" makeElement() makes the previous woord an tag and close                {{{1
if !exists('*s:makeElement')
function! s:makeElement()
  let b:tagName = @@
  let b:haveAtt = 0
  let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
  let l:endOfLine = ((col('.')+1) == col('$'))
  normal! i<pf>
  if b:html_mode && b:tagName =~? b:emptyTags
    if b:haveAtt == 0
      call s:Callback (b:tagName, b:html_mode)
    endif
    if b:xml_use_xhtml
      exe "normal! i/\<Esc>l"
    en
    if  l:endOfLine
      start!
    el
      normal! l
      start
    en
  el
    if b:haveAtt == 0
      call s:Callback (b:tagName, b:html_mode)
    end
    if l:alone
      exe 'normal! o</pa>Ox>>$x'
      start!
    el
      exe 'normal! a</pa>F<'
      start
    en
  en
endfunction
en

" CloseTagFun() closing the tag which is being typed                  {{{1
if !exists('*s:CloseTagFun')
fun! s:CloseTagFun()
  let l:restore =  s:SavePos()
  let l:endOfLine = ((col('.')+1) == col('$'))
  "Some plugin like delimitMate will auto insert the closing '>'
  "Delete it if user input '>' again to trigger xml.vim
  if col('.') > 1 && getline('.')[col('.')] == '>'
    normal! d1l
  en
  if col('.') > 1 && getline('.')[col('.')-2] == '>'
  "Multiline request. <t>></t> -->
  "<t>
  "     cursor comes here
  "</t>
    normal! h
    if s:TagUnderCursor()
      if b:firstWasEndTag == 0
        if exists('b:did_indent') && b:did_indent == 1
          exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>$x"
        else
          exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
        en
        start!
        retu
      en
    en
  elseif s:TagUnderCursor()
    if b:firstWasEndTag == 0
      exe "normal! />\<Cr>"
      if b:html_mode && b:tagName =~?  b:emptyTags
        if b:haveAtt == 0
          call s:Callback (b:tagName, b:html_mode)
        en
        if b:xml_use_xhtml
          exe "normal! i/\<Esc>l"
        en
        if l:endOfLine
          start!
          retu
        el
          normal! l
          start
          retu
        en
      el
        if b:haveAtt == 0
          call s:Callback (b:tagName, b:html_mode)
        en
        exe "normal! a</" . b:tagName . ">\<Esc>F<"
        start
        retu
      en
    en
  en
  exe l:restore
  if (col('.')+1) == col("$")
    startinsert!
  else
    normal! l
    startinsert
  en
endf
en

" BlockTag() Surround a visual block with a tag                       {{{1
" Be carefull where You place the block
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:BlockTag')
fun! s:BlockTag(multi)
  let l:newname = inputdialog('Surround block  with : ',b:lastTag)
  if strlen( l:newname) == 0
    retu
  en
  let b:lastTag =  l:newname
  let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
  if strlen(l:newatt)
    let b:lastAtt = l:newatt
  en

  "Get at the end of the block
  if col('.') == col("'<") && line('.') == line("'<")
    normal! gvov
  en
  if a:multi
    exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
    let l:eline = line('.')
    normal! gvov
    if col('.') == col("'>") && line('.') == line("'>")
      normal! gvov
    en
    let l:sline = line(".") + 2
    exe "normal! i\<Cr><".l:newname.
      \ (strlen(l:newatt) ? ' '.l:newatt : '' )
      \ .">\<Cr>\<Esc>"
      let l:rep=&report
      let &report=999999
      exe l:sline.','.l:eline.'>'
      let &report= l:rep
      exe 'normal! '.l:sline.'G0mh'.l:eline."G$v'hgq"
  el
    exe "normal! a</".l:newname.">\<Esc>gvov"
    if col('.') == col("'>") && line('.') == line("'>")
      normal! gvov
    en
    exe "normal! i<".l:newname.
      \ (strlen(l:newatt) ? ' '.l:newatt : '' )
      \ .">\<Esc>"
  en
endf
en
" BlockWith() Surround a visual block with a open and a close          {{{1
" Be carefull where You place the block
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:BlockWith')
fun! s:BlockWith(open,close)
  if col('.') == col("'<") && line('.') == line("'<")
    normal! gvov
  en
  exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
  normal! gvov
  exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
endf
en
" vlistitem() Surround a visual block with a listitem para tag      {{{1
" Be carefull where You place the block
" the top    is done with insert!
" the bottem is done with append!
if !exists('*s:vlistitem')
fun! s:vlistitem()
  "Get at the end of the block
  if col('.') == col("'<") && line('.') == line("'<")
    normal! gvov
  en
  exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
  normal! gvov
  exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
endf
en
" Change() Only renames the tag                                         {{{1
if !exists('*s:Change')
fun! s:Change()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
    if strlen( l:newname) == 0
      retu
    en
    let b:lastTag =  l:newname
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      exe 'normal! 2lcw' . l:newname . "\<Esc>"
      exe b:gotoOpenTag
      exe 'normal! lcw' . l:newname . "\<Esc>"
    en
  en
endf
en

" Join() Joins two the same tag adjacent sections                    {{{1
if !exists('*s:Join')
fun! s:Join()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
    let l:flags='W'
    if  b:firstWasEndTag == 0
      let l:flags='Wb'
    en
    if search(s:OpenOrCloseTag,l:flags) > 0

      let l:secondChar = getline('.')[col('.')]
      if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
        exe l:restore
        retu
      en
      let l:end = 0
      if l:secondChar == '/'
        let l:end = 1
      en
      let l:name = s:GetTagName(col('.') + l:end)
      if l:name == b:tagName
        if b:firstWasEndTag
          let b:gotoOpenTag = s:SavePos()
        el
          let b:gotoCloseTag = s:SavePos()
        en
        let l:DeleteTag  = "normal! d/>/e\<Cr>"
        exe b:gotoCloseTag
        exe l:DeleteTag
        exe b:gotoOpenTag
        exe l:DeleteTag
      en
    en
  en
  exe l:restore
endf
en

" ChangeWholeTag() removes attributes and rename tag                     {{{1
if !exists('*s:ChangeWholeTag')
fun! s:ChangeWholeTag()
  if s:TagUnderCursor()
    let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
    if strlen(l:newname) == 0
      retu
    en
    let b:lastTag =  l:newname
    let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
    if strlen(l:newatt)
      let b:lastAtt = l:newatt
    en
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      exe "normal! 2lc/>\<Cr>".l:newname."\<Esc>"
      exe b:gotoOpenTag
      exe "normal! lc/>/\<Cr>".l:newname.
      \ (strlen(l:newatt) ? ' '.l:newatt : '' )
      \."\<Esc>"
    en
  en
endf
en

" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah'            {{{1
if !exists('*s:Delete')
fun! s:Delete()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    if s:Match(b:tagName)
      let l:DeleteTag  = "normal! d/>/e\<Cr>"
      exe b:gotoCloseTag
      exe l:DeleteTag
      exe b:gotoOpenTag
      exe l:DeleteTag
    en
  else
    exe l:restore
  en
endf
en


" DeleteSection() Deletes everything between start of open tag and end of  {{{1
" closing tag
if !exists('*s:DeleteSection')
fun! s:DeleteSection()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    if s:Match(b:tagName)
      let l:sentinel = 'XmLSeNtInElXmL'
      let l:len = strlen(l:sentinel)
      let l:rep=&report
      let &report=999999
      exe b:gotoCloseTag
      exe "normal! />\<Cr>a".l:sentinel."\<Esc>"
      exe b:gotoOpenTag
      exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
      exe "normal! ".l:len."x"
      let &report= l:rep
    en
  en
endf
en
"
" FoldTag() Fold the tag under the cursor                           {{{1
if !exists('*s:FoldTag')
fun! s:FoldTag()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
  let l:sline = line('.')
    if s:Match(b:tagName)
      if b:firstWasEndTag
        exe '.,'.l:sline.'fold'
      el
        exe l:sline.',.fold'
      en
    en
  el
    exe l:restore
  en
endf
en

" FoldTagAll() Fold all tags of under the cursor             {{{1
" If no tag under the cursor it asks for a tag
if !exists('*s:FoldTagAll')
fun! s:FoldTagAll()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:tname = b:tagName
  el
    let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
    if strlen(l:tname) == 0
      exe l:restore
      retu
    en
    let b:lastTag =  l:tname
  en
  normal! G$
  let l:flag='w'
  while search('<'.l:tname.s:OptAttrib,l:flag) > 0
    let l:flag='W'
    let l:sline = line('.')
    let l:level = 1
    while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
      let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
    endwhile
    if l:level == 0
      exe l:sline.',.fold'
    el
      let l:tmp =
        \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
      break
    en
  endwhile
  exe l:restore
endf
en


" StartTag() provide the opening tag                                    {{{1
if !exists('*s:StartTag')
fun! s:StartTag()
  let l:restore = s:SavePos()
  let l:level = 1
  if getline('.')[col('.')-1] == '<'
    if s:TagUnderCursor()
      if b:firstWasEndTag
        exe 'normal! i<'. b:tagName.">\<Esc>F<"
        retu
      el
        let l:level = l:level + 1
      en
    en
    exe l:restore
  en
  while l:level && search(s:OpenOrCloseTag ,'W') > 0
    let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
  endwhile
  if l:level == 0
    let l:Name = s:GetTagName(col('.') + 1)
    exe l:restore
    exe 'normal! i<'. l:Name.">\<Esc>"
  en
  exe l:restore
endf
en



" EndTag() search for open tag and produce endtaf                 {{{1
if !exists('*s:EndTag')
fun! s:EndTag()
  let l:restore = s:SavePos()
  let l:level = -1
  while l:level && search(s:OpenOrCloseTag,'bW') > 0
    let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
  endwhile
  if l:level == 0
    let l:Name = s:GetTagName(col('.'))
    exe  l:restore
    exe 'normal! a</'. l:Name.">\e"
  el
    exe  l:restore
  en
endf
en


" BeforeTag() surrounds the current tag with a new one                   {{{1
if !exists('*s:BeforeTag')
fun! s:BeforeTag()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:newname =
      \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
    if strlen(l:newname) == 0
      retu
    en
    let b:lastTag = l:newname
    let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
    if strlen(l:newatt)
      let b:lastAtt = l:newatt
    en
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
      let l:To = line('.')
      exe b:gotoOpenTag
      exe 'normal! i<' . l:newname .
        \ (strlen(l:newatt) ? ' '.l:newatt : '' )
        \.">\<Cr>\<Esc>"
      let l:rep=&report
      let &report=999999
      exe line('.').','.l:To.'>'
      let &report= l:rep
    en
    exe  l:restore
  en
endf
en

" CommentTag() surrounds the current tag with a new one                   {{{1
if !exists('*s:CommentTag')
fun! s:CommentTag()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
      let l:To = line('.')
      exe b:gotoOpenTag
      exe "normal! i<!--\<Cr>\<Esc>"
      let l:rep=&report
      let &report=999999
      exe line('.').','.l:To.'>'
      let &report= l:rep
    en
  else
    exe  l:restore
  en
endf
en
" AfterTag() surrounds the tags after the current one with new      {{{1
if !exists('*s:AfterTag')
fun! s:AfterTag()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:newname =
      \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
    if strlen(l:newname) == 0
      retu
    en
    let b:lastTag = l:newname
    let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
    if strlen(l:newatt)
      let b:lastAtt = l:newatt
    en
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
      let l:To = line('.')
      exe b:gotoOpenTag
      exe "normal! />\<Cr>a\<Cr><".l:newname.
        \ (strlen(l:newatt) ? ' '.l:newatt : '' )
        \.">\<Esc>"
      let l:rep=&report
      let &report=999999
      exe line('.').','.l:To.'>'
      let &report= l:rep
    en
  en
  exe  l:restore
endf
en
" ShiftRight() Shift the tag to the right                               {{{1
if !exists('*s:ShiftRight')
fun! s:ShiftRight()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:sline = line('.')
    if s:Match(b:tagName)
      let l:eline = line('.')
      if b:firstWasEndTag
        exe l:eline.','.l:sline.'>'
      el
        exe l:sline.','.l:eline.'>'
      en
    en
  en
endf
en

" ShiftLeft() Shift the tag to the left                                {{{1
if !exists('*s:ShiftLeft')
fun! s:ShiftLeft()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:sline = line('.')
    if s:Match(b:tagName)
      let l:eline = line('.')
      if b:firstWasEndTag
        exe l:eline.','.l:sline.'<'
      el
        exe l:sline.','.l:eline.'<'
      en
    en
  en
endf
en
" FormatTag() visual select the block and use gq                    {{{1
if !exists('*s:FormatTag')
fun! s:FormatTag()
  if s:TagUnderCursor()
    if s:Match(b:tagName)
      exe b:gotoCloseTag
      normal! hhmh
      exe b:gotoOpenTag
      exe "normal! />/e+1\<Cr>v'hgq"
    en
  en
endf
en




" FormatTagAll() Format all tags of name under the cursor             {{{1
" If no tag under the cursor it asks for a tag
if !exists('*s:FormatTagAll')
fun! s:FormatTagAll()
  let l:restore = s:SavePos()
  if s:TagUnderCursor()
    let l:tname = b:tagName
  el
    let l:tname = inputdialog('Format every tag : ')
    if strlen(l:tname) == 0
      exe l:restore
      retu
    en
  en
  normal! G$
  let l:flag = 'w'
  while search('<'.l:tname . s:OptAttrib, l:flag) > 0
    let l:flag = 'W'
    let l:sline = line('.')
    let l:level = 1
    exe "normal! />/e+1\<cr>mh"
    while l:level &&  search('</\='.l:tname . s:EndofName,'W') > 0
      let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
    endwhile
    if l:level == 0
      normal! hv'hogq
    el
      let l:tmp =
        \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
      break
    en
  endwhile
  exe l:restore
endf
en


" IndentAll() indent all tags multiline                            {{{1
if !exists('*s:IndentAll')
fun! s:IndentAll()

  let l:restore = s:SavePos()
      let l:rep=&report
      let &report=999999
  "shift everything left
  normal! 1G<G<G<G<G<G<GG$
  if search(s:OpenTag,'w') > 0
    let l:level = 1
    normal! f>
    "if there is something after the tag move that to the next line
    if col('.')+1 != col('$')
      echo "after tag".line('.')
      exe "normal! a\<Cr>\<Esc>"
    el
      normal! j
    en
    normal! >Gk$
    while search(s:OpenOrCloseTag,'W') > 0
      "if there is text before the tag then move the tag to the next line
      if  match(getline('.'),s:SpaceInfront) == -1
        exe "normal! i\<Cr>\<Esc>l"
      en
      if getline('.')[col('.')] == '/'
        normal! <G0f>
        "if there is something after the tag move that to the next line
        if col('.')+1 != col('$')
          exe "normal! a\<Cr>\<Esc>"
        en
        let l:level = l:level - 1
      el
        normal! f>
        "if there is something after the tag move that to the next line
        if col('.')+1 != col('$')
          exe "normal! a\<Cr>\<Esc>"
        el
          normal! j0
        en
        normal! >Gk$
        let l:level = l:level + 1
      en
    endwhile
    if l:level
      let l:tmp =
      \ inputdialog("The tags opening and closing are unbalanced ".l:level)
    en
  en
  exe l:restore
  let &report= l:rep
endf
en


" mapKey()                         {{{1
function! s:mapKey(mode, key, cmd)
  if maparg(a:key, a:mode) == ''
    execute a:mode . "noremap <silent> <buffer> " .
          \ a:key . " " .
          \ a:cmd
    let b:xmlPluginMappedKeys += [[a:mode, a:key]]

  elseif exists("g:xml_warn_on_duplicate_mapping")
        \ && g:xml_warn_on_duplicate_mapping

    redraw
    let s:duplicate_mapping_msg = 'Mapping already exists: ' .
          \ a:key .
          \ " in mode " . a:mode
    echohl WarningMsg | echomsg s:duplicate_mapping_msg | echohl None
  endif
endfunction

" unmapKeys()                         {{{1
function! s:unmapKeys()
  for mapped in b:xmlPluginMappedKeys
    execute "silent! " . mapped[0] . "unmap <buffer> " . mapped[1]
  endfor
  let b:xmlPluginMappedKeys = []
endfunction

" Menu options: {{{1
augroup XML_menu_autos
au!
autocmd BufLeave,BufWinLeave *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
   \ amenu disable Xml |
   \ amenu disable Xml.* |
 \ endif
autocmd BufEnter,BufWinEnter *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
   \ amenu enable Xml |
   \ amenu enable Xml.* |
 \ endif
au BufNewFile *
 \ if &filetype == "xml" ||  &filetype == "html" ||  &filetype == "xhtml" |
     \ call NewFileXML() |
   \ endif
augroup END
if !exists("g:did_xml_menu")
  let g:did_xml_menu = 1
  :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V  <Esc>:call <SID>BlockTag(1)<Cr>
  vmenu <script> Xml.BlockTag\ inline<Tab>v  <Esc>:call <SID>BlockTag(0)<CR>
  vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
  vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
  vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
  nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
  imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
  nmenu <script> Xml.Change<Tab>c  :call <SID>Change()<CR>
  imenu <script> Xml.Change<Tab>c  <C-C>:call <SID>Change()<CR>
  nmenu <script> Xml.Change\ Whole\ Tag<Tab>C  :call <SID>ChangeWholeTag()<CR>
  imenu <script> Xml.Change\ Whole\ Tag<Tab>C  <C-C>:call <SID>ChangeWholeTag()<CR>
  nmenu <script> Xml.Delete\ Comment<Tab>]  :call <SID>DelComment()<CR>
  imenu <script> Xml.Delete\ Comment<Tab>]  <C-C>:call <SID>DelComment()<CR>
  nmenu <script> Xml.Delete\ Comment\ Section<Tab>}  :call <SID>DelCommentSection()<CR>
  imenu <script> Xml.Delete\ Comment\ Section<Tab>}  <C-C>:call <SID>DelCommentSection()<CR>
  nmenu <script> Xml.Delete\ CData<Tab>[  :call <SID>DelCData()<CR>
  imenu <script> Xml.Delete\ CData<Tab>[  <C-C>:call <SID>DelCData()<CR>
  nmenu <script> Xml.Delete\ CData\ Section<Tab>[  :call <SID>DelCDataSection()<CR>
  imenu <script> Xml.Delete\ CData\ Section<Tab>[  <C-C>:call <SID>DelCDataSection()<CR>
  nmenu <script> Xml.Delete\ Tag<Tab>d  :call <SID>Delete()<CR>
  imenu <script> Xml.Delete\ Tag<Tab>d  <C-C>:call <SID>Delete()<CR>
  nmenu <script> Xml.Delete\ Section<Tab>D  :call <SID>DeleteSection()<CR>
  imenu <script> Xml.Delete\ Section<Tab>D  <C-C>:call <SID>DeleteSection()<CR>
  nmenu <script> Xml.End\ Tag<Tab>e  :call <SID>EndTag()<CR>
  imenu <script> Xml.End\ Tag<Tab>e  <C-C>:call <SID>EndTag()<CR>
  nmenu <script> Xml.Fold\ Comment  :?<!--?,/-->/fo<CR>
  nmenu <script> Xml.Fold\ CData  :?<!\[CDATA\[?,/\]\]>/fo<CR>
  nmenu <script> Xml.Fold\ Processing\ instruc  :?<\?[a-zA-Z]*?,/?>/fo<CR>
  nmenu <script> Xml.Fold\ Tag<Tab>f  :call <SID>FoldTag()<CR>
  nmenu <script> Xml.Fold\ All\ Tags<Tab>F  :call <SID>FoldTagAll()<CR>
  nmenu <script> Xml.Format\ Tags<Tab>g  :call <SID>FormatTag()<CR>
  nmenu <script> Xml.Format\ All\ Tags<Tab>G  :call <SID>FormatTagAll()<CR>
  nmenu <script> Xml.Join<Tab>j  :call <SID>Join()<CR>
  imenu <script> Xml.Join<Tab>j  <C-C>:call <SID>Join()<CR>
  nmenu <script> Xml.Open\ After\ Tag<Tab>O  :call <SID>AfterTag()<CR>
  imenu <script> Xml.Open\ After\ Tag<Tab>O  <C-C>:call <SID>AfterTag()<CR>
  nmenu <script> Xml.open\ Before\ Tag<Tab>o  :call <SID>BeforeTag()<CR>
  imenu <script> Xml.open\ Before\ Tag<Tab>o  <C-C>:call <SID>BeforeTag()<CR>
  nmenu <script> Xml.Match<Tab>5  :call <SID>Matches()<CR>
  imenu <script> Xml.Match<Tab>5  <C-C>:call <SID>Matches()<CR><C-\><C-G>
  nmenu <script> Xml.Shift\ Left<Tab><  :call <SID>ShiftLeft()<CR>
  imenu <script> Xml.Shift\ Left<Tab><  <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
  nmenu <script> Xml.Shift\ Right<Tab>>  :call <SID>ShiftRight()<CR>
  imenu <script> Xml.Shift\ Right<Tab>>  <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
  nmenu <script> Xml.Start\ Tag<Tab>s  :call <SID>StartTag()<CR>
  imenu <script> Xml.Start\ Tag<Tab>s  <C-C>:call <SID>StartTag()<CR><C-\><C-G>
endif

function! s:XmlInstallDocumentation(full_name, revision)
    " Name of the document path based on the system we use:
    if (has("unix"))
        " On UNIX like system, using forward slash:
        let l:slash_char = '/'
        let l:mkdir_cmd  = ':silent !mkdir -p '
    else
        " On M$ system, use backslash. Also mkdir syntax is different.
        " This should only work on W2K and up.
        let l:slash_char = '\'
        let l:mkdir_cmd  = ':silent !mkdir '
    endif

    let l:doc_path = l:slash_char . 'doc'
    "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'

    " Figure out document path based on full name of this script:
    let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
    "let l:vim_doc_path   = fnamemodify(a:full_name, ':h:h') . l:doc_path
    let l:vim_doc_path    = matchstr(l:vim_plugin_path,
                \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
    if (!(filewritable(l:vim_doc_path) == 2))
        echomsg "Doc path: " . l:vim_doc_path
        execute l:mkdir_cmd . '"' . l:vim_doc_path . '"'
        if (!(filewritable(l:vim_doc_path) == 2))
            " Try a default configuration in user home:
            "let l:vim_doc_path = expand("~") . l:doc_home
            let l:vim_doc_path = matchstr(&rtp,
                        \ escape($HOME, ' \') .'[/\\]\%(\.vim\|vimfiles\)')
            if (!(filewritable(l:vim_doc_path) == 2))
                execute l:mkdir_cmd . l:vim_doc_path
                if (!(filewritable(l:vim_doc_path) == 2))
                    " Put a warning:
                    echomsg "Unable to open documentation directory"
                    echomsg " type :help add-local-help for more informations."
                    return 0
                endif
            endif
        endif
    endif

    " Exit if we have problem to access the document directory:
    if (!isdirectory(l:vim_plugin_path)
                \ || !isdirectory(l:vim_doc_path)
                \ || filewritable(l:vim_doc_path) != 2)
        return 0
    endif

    " Full name of script and documentation file:
    let l:script_name = 'xml.vim'
    let l:doc_name    = 'xml-plugin.txt'
    let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
    let l:doc_file    = l:vim_doc_path    . l:slash_char . l:doc_name

    " Bail out if document file is still up to date:
    if (filereadable(l:doc_file)  &&
                \ getftime(l:plugin_file) < getftime(l:doc_file))
        return 0
    endif

    " Prepare window position restoring command:
    if (strlen(@%))
        let l:go_back = 'b ' . bufnr("%")
    else
        let l:go_back = 'enew!'
    endif

    " Create a new buffer & read in the plugin file (me):
    setl nomodeline
    exe 'enew!'
    exe 'r ' . l:plugin_file

    setl modeline
    let l:buf = bufnr("%")
    setl noswapfile modifiable

    norm zR
    norm gg

    " Delete from first line to a line starts with
    " === START_DOC
    1,/^=\{3,}\s\+START_DOC\C/ d

    " Delete from a line starts with
    " === END_DOC
    " to the end of the documents:
    /^=\{3,}\s\+END_DOC\C/,$ d

    " Remove fold marks:
    "% s/{\{3}[1-9]/    /

    " Add modeline for help doc: the modeline string is mangled intentionally
    " to avoid it be recognized by VIM:
    call append(line('$'), '')
    call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')

    " Replace revision:
    exe "normal! :1,5s/#version#/ v" . a:revision . "/\<CR>"

    " Save the help document:
    exe 'w! ' . l:doc_file
    exe l:go_back
    exe 'bw ' . l:buf

    " Build help tags:
    exe 'helptags ' . l:vim_doc_path

    return 1
endfunction
" }}}2

let s:revision=
            \ substitute("$Revision: 1.36 $",'\$\S*: \([.0-9]\+\) \$','\1','')
silent! let s:install_status =
            \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
if (s:install_status == 1)
    echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
                \ ': Help-documentation installed.'
endif


" Mappings                                                                {{{1

call s:unmapKeys()

" Mappings of keys to functions                                         {{{2
call <SID>mapKey('n', '<LocalLeader>5', ':call <SID>Matches()<Cr>')
call <SID>mapKey('v', '<LocalLeader>5', '<Esc>:call <SID>MatchesVisual()<Cr>')
call <SID>mapKey('n', '<LocalLeader>%', ':call <SID>Matches()<Cr>')
call <SID>mapKey('v', '<LocalLeader>%', '<Esc>:call <SID>MatchesVisual()<Cr>')
call <SID>mapKey('n', '<LocalLeader>c', ':call <SID>Change()<Cr>')
call <SID>mapKey('n', '<LocalLeader>C', ':call <SID>ChangeWholeTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>d', ':call <SID>Delete()<Cr>')
call <SID>mapKey('n', '<LocalLeader>D', ':call <SID>DeleteSection()<Cr>')
call <SID>mapKey('n', '<LocalLeader>e', ':call <SID>EndTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>]', ':call <SID>DelComment()<Cr>')
call <SID>mapKey('n', '<LocalLeader>}', ':call <SID>DelCommentSection()<Cr>')
call <SID>mapKey('n', '<LocalLeader>f', ':call <SID>FoldTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>F', ':call <SID>FoldTagAll()<Cr>')
call <SID>mapKey('n', '<LocalLeader>g', ':call <SID>FormatTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>G', ':call <SID>FormatTagAll()<Cr>')
call <SID>mapKey('n', '<LocalLeader>I', ':call <SID>IndentAll()<Cr>')
call <SID>mapKey('n', '<LocalLeader>j', ':call <SID>Join()<Cr>')
call <SID>mapKey('n', '<LocalLeader>O', ':call <SID>BeforeTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>=', ':call <SID>CommentTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>o', ':call <SID>AfterTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>s', ':call <SID>StartTag()<Cr>')
call <SID>mapKey('n', '<LocalLeader>[', ':call <SID>DelCData()<Cr>')
call <SID>mapKey('n', '<LocalLeader>{', ':call <SID>DelCDataSection()<Cr>')
call <SID>mapKey('n', '<LocalLeader>>', ':call <SID>ShiftRight()<Cr>')
call <SID>mapKey('n', '<LocalLeader><', ':call <SID>ShiftLeft()<Cr>')
call <SID>mapKey('v', '<LocalLeader>l', '<Esc>:call <SID>vlistitem()<Cr>')
call <SID>mapKey('v', '<LocalLeader>v', '<Esc>:call <SID>BlockTag(0)<Cr>')
call <SID>mapKey('v', '<LocalLeader>V', '<Esc>:call <SID>BlockTag(1)<Cr>')
call <SID>mapKey('v', '<LocalLeader>c', '<Esc>:call <SID>BlockWith("<![CDATA[","]]>")<Cr>')
call <SID>mapKey('v', '<LocalLeader><', '<Esc>:call <SID>BlockWith("<!--","-->")<Cr>')

" Move around functions                                                 {{{2
call <SID>mapKey('n', '[[', "m':call <SID>findOpenTag('bW')<CR>")
call <SID>mapKey('n', ']]', "m':call <SID>findOpenTag('W')<CR>")
call <SID>mapKey('n', '[]', "m':call <SID>findCloseTag('bW')<CR>")
call <SID>mapKey('n', '][', "m':call <SID>findCloseTag('W')<CR>")

" Move around comments                                                  {{{2
call <SID>mapKey('n', ']"', substitute(':call search("^\(\s*<!--.*\n\)\@<!\(\s*-->\)", "W")<CR>', '"', "'", 'g'))
call <SID>mapKey('n', '["', substitute(':call search("\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!", "bW")<CR>', '"', "'", 'g'))

" insert mode shortcuts                                                 {{{2
call <SID>mapKey('i', b:suffix, ' ><Esc>db:call <SID>makeElement()<Cr>')
if !exists("g:xml_tag_completion_map")
    call <SID>mapKey('i', '>', ' ><Esc>:call <SID>CloseTagFun()<Cr>')
else
    call <SID>mapKey('i', g:xml_tag_completion_map, ' ><Esc>:call <SID>CloseTagFun()<Cr>')
endif
